using System;
using BankInvest.InstrumentEditor.Controllers;
using BankInvest.InstrumentEditor.Domain.Entities;
using BankInvest.InstrumentEditor.NHibernate;
using NSubstitute;
using NUnit.Framework;
using SharpTestsEx;
using StoryQ;
using StructureMap;

namespace BankInvest.InstrumentEditor.Tests.AcceptanceTests
{
    [TestFixture, Category( "Story" )]
    public class EditInstrumentStory
    {
        private IInstrumentEditorView _instrumentEditorViewMock;
        private InstrumentEditorController _instrumentEditorController;

        private readonly Feature _story =
            new Story( "Edit Instrument" )
            .InOrderTo("support the business.")
            .AsA("BankInvest employee.")
            .IWant("to create new instruments, as well as find and update existing ones.");

        [SetUp]
        public void StartTheApplication()
        {
            _instrumentEditorViewMock = Substitute.For<IInstrumentEditorView>();

            new SqliteInMemoryAppConfigurator().Configure();
            ObjectFactory.Inject(_instrumentEditorViewMock);

            _instrumentEditorController = ObjectFactory.GetInstance<InstrumentEditorController>();
            _instrumentEditorController.InitializeInstrumentEditorView();
        }

        [TearDown]
        public void CloseTheApplication()
        {
            _instrumentEditorController.Dispose();
        }

        [Test]
        public void Create_Instrument()
        {
            _story.WithScenario(
                s => s.WithNamedScenario()
                .Given(ITypedANewUniqueAndValidId)
                    .And(TypedAValidName)
                    .And(SelectedBondAsInstrumentType)
                .When(IClickTheSaveButton)
                .Then(TheStatusFieldSaysThatTheInstrumentWasSuccessfullyCreated)
                    .And(AnActiveInstrumentWithTheTypedIdNameAndTypeIsFoundInTheDatabase));
        }

        [Test]
        public void Find_Instrument()
        {
            _story.WithScenario(
                s => s.WithNamedScenario()
                .Given(ITypedAnExistingId)
                .When(IClickTheFindByIdButton)
                .Then(TheStatusFieldSaysThatTheInstrumentWasFound)
                    .And(TheIdFieldIsFilledOutWithTheExistingId)
                    .And(TheNameFieldIsFilledOutWithTheNameOfTheFoundInstrument)
                    .And(TheSelectedItemOfTheTypeDropdownIsTheTypeOfTheFoundInstrument)
                    .And(TheActiveCheckboxIsChecked));
        }

        [Test]
        public void Update_Instrument_case_Inactivate()
        {
            _story.WithScenario(
                s => s.WithNamedScenario()
                .Given(ITypedAnExistingId)
                .When(IClickTheFindByIdButton)
                    .And(IUncheckTheActiveCheckbox)
                    .And(IClickTheSaveButton)
                .Then(TheStatusFieldSaysThatTheInstrumentWasSuccessfullyUpdated)
                    .And(TheInstrumentIsInactiveInTheDatabase));
        }

        private void ITypedANewUniqueAndValidId()
        {
            _instrumentEditorViewMock.Id = "34218GH";
        }

        private void TypedAValidName()
        {
            _instrumentEditorViewMock.InstrumentName = "Grenada High Interest Bond 9%";
        }

        private void SelectedBondAsInstrumentType()
        {
            _instrumentEditorViewMock.SelectedInstrumentTypeId = 1;
        }

        private void TheStatusFieldSaysThatTheInstrumentWasSuccessfullyCreated()
        {
            _instrumentEditorViewMock.Received().Status = 
                Arg.Is<String>(msg => msg.StartsWith("Instrument")
                                    && msg.EndsWith("successfully saved."));
        }

        private void AnActiveInstrumentWithTheTypedIdNameAndTypeIsFoundInTheDatabase()
        {
            var unitOfWork = ObjectFactory.GetInstance<IUnitOfWork>();

            var session = unitOfWork.CurrentSession;

            var instrument = session.Get<Instrument>("34218GH");

            unitOfWork.Commit();

            instrument.Name.Should().Be.EqualTo("Grenada High Interest Bond 9%");
            instrument.IsActive.Should().Be.True();
            instrument.Type.Should().Be.EqualTo(new InstrumentType(1));
        }

        private void TheStatusFieldSaysThatTheInstrumentWasFound()
        {
            _instrumentEditorViewMock.Received().Status = Arg.Is<String>(msg => msg.StartsWith("Instrument")
                                                                             && msg.EndsWith("found."));
        }

        private void TheIdFieldIsFilledOutWithTheExistingId()
        {
            _instrumentEditorViewMock.Received().Id = "890898";
        }

        private void TheNameFieldIsFilledOutWithTheNameOfTheFoundInstrument()
        {
            _instrumentEditorViewMock.Received().InstrumentName = "6% Kommunekredit 47s.A 2006";
        }

        private void TheSelectedItemOfTheTypeDropdownIsTheTypeOfTheFoundInstrument()
        {
            _instrumentEditorViewMock.Received().SelectedInstrumentTypeId = 1;
        }

        private void TheActiveCheckboxIsChecked()
        {
            _instrumentEditorViewMock.Received().IsActive = true;
        }

        private void ITypedAnExistingId()
        {
            _instrumentEditorViewMock.Id = "890898";
        }

        private void IClickTheFindByIdButton()
        {
            _instrumentEditorViewMock.FindById += Raise.Event<Action>();
        }

        private void IUncheckTheActiveCheckbox()
        {
            _instrumentEditorViewMock.IsActive = false;
        }

        private void IClickTheSaveButton()
        {
            _instrumentEditorViewMock.Save += Raise.Event<Action>();
        }

        private void TheStatusFieldSaysThatTheInstrumentWasSuccessfullyUpdated()
        {
            _instrumentEditorViewMock.Received().Status = Arg.Is<String>(msg => msg.StartsWith("Instrument")
                                                                             && msg.EndsWith("successfully saved."));
        }

        private void TheInstrumentIsInactiveInTheDatabase()
        {
            var unitOfWork = ObjectFactory.GetInstance<IUnitOfWork>();

            var session = unitOfWork.CurrentSession;

            var instrument = session.Get<Instrument>("890898");

            unitOfWork.Commit();

            instrument.IsActive.Should().Be.False();
        }
    }
}